﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="EngineBootStrapper.cs" company="dimamartovoi">
//   Apache License
//   Version 2.0, January 2004
//   http://www.apache.org/licenses
// </copyright>
// <summary>
//   The engine bootstrapper.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using ActorModel.Engine.Core;

namespace ActorModel.Infrastructure
{
    /// <summary>
    /// The engine bootstrapper.
    /// </summary>
    /// <typeparam name="TState">
    /// </typeparam>
    public sealed class EngineBootstrapper<TState>
    {
        #region Fields

        /// <summary>
        ///     The start parameters.
        /// </summary>
        private readonly EngineStartParameters<TState> startParameters;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="EngineBootstrapper{TState}"/> class.
        /// </summary>
        /// <param name="startParameters">
        /// The start parameters.
        /// </param>
        public EngineBootstrapper(EngineStartParameters<TState> startParameters)
        {
            this.startParameters = startParameters;
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        ///     The initialize.
        /// </summary>
        /// <returns>
        ///     The <see>
        ///             <cref>IEngineFlowController</cref>
        ///         </see>
        ///     .
        /// </returns>
        public IEngineFlowController<TState> Initialize()
        {
            var notifier = new StateChangingNotifier<TState>();
            var nodes = new Node<TState>[this.startParameters.NumberOfNodes];
            for (int i = 0; i < this.startParameters.NumberOfNodes; i++)
            {
                var connectors = new Connector<TState>[this.startParameters.NumberOfNodeConnectors];
                for (int j = 0; j < this.startParameters.NumberOfNodeConnectors; j++)
                {
                    int id = (i * this.startParameters.NumberOfNodeConnectors) + j;
                    ConnectorInfo<TState> connectorInfo = this.startParameters.ConnectorsInfo[id];
                    var connector = new Connector<TState>(connectorInfo.State, id, connectorInfo.TargetConnectorId, notifier);
                    connectors[j] = connector;
                    
                }

                var node = new Node<TState>(
                    i, this.startParameters.NodesInitialStates[i], connectors, this.startParameters.EvolutionFunc);
                foreach (var connector in connectors)
                {
                    connector.ConnectorsPerNodeCount = (uint)this.startParameters.NumberOfNodeConnectors;
                }

                nodes[i] = node;
            }

            var flowController = new EngineFlowController<TState>(nodes);
            return flowController;
        }

        #endregion
    }
}